using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
namespace MapWindow.Drawing
{
    /// <summary>
    /// This contains the pen information with OGC conventions, but can have the pens property
    /// specified directly for additional control.
    /// </summary>
    public class Stroke
    {
        #region Variables

        Color _Color = Color.Black;
        float _Width = 1.0f;
        float _Opacity = 1.0f;
        LineJoinTypes _LineJoin = LineJoinTypes.Round;
        LineCapTypes _LineCap = LineCapTypes.Round;
        float[] _DashArray;
        float _DashOffset = 0.0f;
        Image _GraphicFill;
        Image _GraphicStroke;

        #endregion

        #region Constructors

        /// <summary>
        /// This creates a new instance of an OGC stroke given a System.Drawing.Pen
        /// </summary>
        /// <param name="pen"></param>
        public Stroke(System.Drawing.Pen pen)
        {
            if (pen.Brush is TextureBrush)
            {
                _GraphicFill = ((TextureBrush)pen.Brush).Image;
                // Not sure how to handle opacity here
            }
            else
            {
                _Color = pen.Color;
                _Opacity = ((float)pen.Color.A) / 255f;
            }
            _DashArray = pen.DashPattern;
            _DashOffset = pen.DashOffset;
            switch (pen.StartCap)
            {
                case System.Drawing.Drawing2D.LineCap.Round:
                    _LineCap = LineCapTypes.Round;
                    break;
                case System.Drawing.Drawing2D.LineCap.Square:
                    _LineCap = LineCapTypes.Square;
                    break;
                case System.Drawing.Drawing2D.LineCap.Triangle:
                    _LineCap = LineCapTypes.Butt;
                    break;
                default:
                    _LineCap = LineCapTypes.Round;
                    break;
            }
            switch (pen.LineJoin)
            {
                case System.Drawing.Drawing2D.LineJoin.Bevel:
                    _LineJoin = LineJoinTypes.Bevel;
                    break;
                case System.Drawing.Drawing2D.LineJoin.Miter:
                    _LineJoin = LineJoinTypes.Mitre;
                    break;
                case System.Drawing.Drawing2D.LineJoin.Round:
                    _LineJoin = LineJoinTypes.Round;
                    break;
                default:
                    _LineJoin = LineJoinTypes.Round;
                    break;
            }
        }

        #endregion

        #region Methods
        /// <summary>
        /// The Stroke is an OGC standard, while the Pen is part of Dot Net.
        /// The two are more or less interchangeable, but not always identical, and
        /// GDI+ doesn't seem to do the Graphic Stroke at all.
        /// </summary>
        /// <returns></returns>
        public System.Drawing.Pen ToPen()
        {
            Pen p = new Pen(Color.Black);
            if (GraphicFill != null)
            {
                if (_Opacity < 1 && _Opacity > 0)
                {
                    ColorMatrix cm = new ColorMatrix();
                    cm.Matrix00 = cm.Matrix11 = cm.Matrix22 = cm.Matrix44 = 1;
                    cm.Matrix33 = _Opacity; // The first value effects the transparent value ##/100

                    ImageAttributes ia = new ImageAttributes();
                    ia.SetColorMatrix(cm);
                    p = new Pen(new TextureBrush(_GraphicFill, new Rectangle(0, 0, _GraphicFill.Width, _GraphicFill.Height), ia));

                }
                else
                {
                    p = new Pen(new TextureBrush(GraphicFill));
                }
            }
            else
            {
                p.Color = _Color;
                if (_Opacity < 1 && _Opacity > 0)
                {
                    p.Color = Color.FromArgb((int)(255 * _Opacity), _Color);
                }
            }
            switch (_LineCap)
            {
                case LineCapTypes.Butt:
                    p.EndCap = System.Drawing.Drawing2D.LineCap.Triangle;
                    p.StartCap = System.Drawing.Drawing2D.LineCap.Triangle;
                    break;
                case LineCapTypes.Round:
                    p.EndCap = System.Drawing.Drawing2D.LineCap.Round;
                    p.StartCap = System.Drawing.Drawing2D.LineCap.Round;
                    break;
                case LineCapTypes.Square:
                    p.StartCap = System.Drawing.Drawing2D.LineCap.Square;
                    p.EndCap = System.Drawing.Drawing2D.LineCap.Square;
                    break;
            }
            switch (_LineJoin)
            {
                case LineJoinTypes.Bevel:
                    p.LineJoin = System.Drawing.Drawing2D.LineJoin.Bevel;
                    break;
                case LineJoinTypes.Mitre:
                    p.LineJoin = System.Drawing.Drawing2D.LineJoin.Miter;
                    break;
                case LineJoinTypes.Round:
                    p.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;
                    break;
            }
            p.Width = _Width;
            if (_Opacity < 1 && _Opacity > 0)
            {
                if (_GraphicFill != null)
                {
                    Image bob = new Bitmap(_GraphicFill.Width, _GraphicFill.Height);
                    Graphics g = Graphics.FromImage(bob);

                    ColorMatrix cm = new ColorMatrix();
                    cm.Matrix33 = 50; // 50% opacity
                    ImageAttributes ia = new ImageAttributes();
                    ia.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

                    TextureBrush tb = new TextureBrush(_GraphicFill);

                }
            }
            p.DashPattern = _DashArray;
            p.DashOffset = _DashOffset;
            return p;
        }


        #endregion

        #region Properties


        /// <summary>
        /// The Solid color that will be used for a stroke.  The default is black.
        /// </summary>
        public Color Color
        {
            get { return _Color; }
            set { _Color = value; } 
           
        }

        /// <summary>
        /// Gets or sets the dash patterns as a series of space separated floats.
        /// The first number gives the length in uoms of dash to draw, the second 
        /// gives the amount of space to leave, and this pattern repeates.  If
        /// an odd number of values is given, then the pattern is expanded by repeating it
        /// twice to give an even number of values.  The default is to draw an unbroken
        /// line.
        /// </summary>
        public float[] DashArray
        {
            get { return _DashArray; }
            set { _DashArray = value; }
        }

        /// <summary>
        /// Gets or sets a float value indicating the distance into the dash pattern
        /// to start drawing.
        /// </summary>
        public float DashOffset
        {
            get { return _DashOffset; }
            set { _DashOffset = value; }
        }

        /// <summary>
        /// Gets or sets the image that will be used to create the texture pen
        /// </summary>
        public System.Drawing.Image GraphicFill
        {
            get { return _GraphicFill; }
            set { _GraphicFill = value; }
        }

        /// <summary>
        /// THIS DOES NOT WORK!  not sure how to do this in GDI+, though 
        /// it seems to be specified in OGC.
        /// </summary>
        public System.Drawing.Image GraphicStroke
        {
            get { return _GraphicStroke; }
            set { _GraphicStroke = value; }
        }

        /// <summary>
        /// Gets or sets the type of line cap that should be used at the end of the lines
        /// </summary>
        public LineCapTypes LineCap
        {
            get { return _LineCap; }
            set { _LineCap = value; }
        }


        /// <summary>
        /// Gets or sets the LineJoinType to be either Mitre, Round, or Bevel, in order
        /// to determine what the lines should look like at the joints between segments.
        /// </summary>
        public LineJoinTypes LineJoin
        {
            get { return _LineJoin; }
            set { _LineJoin = value; }
        }

        /// <summary>
        /// The level of translucency to use when rendering the stroke.
        /// The value is encoded as a floating-point value between 0.0
        /// and 1.0 with 0.0 representing complete transparency and 1.0 representing
        /// completely opaque.  A linear scale of translucency for intermediate values.
        /// </summary>
        public float Opacity
        {
            get { return _Opacity; }
            set { _Opacity = value; }
        }

        /// <summary>
        /// Gets or sets the float width, which gives the absolute width (thickness) of 
        /// a stroke in units of measure as defined in the LineSymbolizer as encoded as
        /// a float.  The default is 1.0.  
        /// </summary>
        public float Width
        {
            get { return _Width; }
            set { _Width = value; }
        }

        #endregion

       
    }
}
